#include "filter.h"
#include <vcg/simplex/face/pos.h>

FairSurface::FairSurface()
{
    lambda = 0.6307f;
    Kpb = 0.1f;
    mu = lambda / (Kpb * lambda -1);    //-0.673156
}

void FairSurface::setVertID()
{
    int idx = 0;
    for(auto &v:_vm->vert){
        v.id = idx++;
    }
}

void FairSurface::nonShrinking(int times,bool local)
{
    if(times == 0){
        return;
    }
    vcg::tri::UpdateTopology<vcgMesh>::VertexFace(*_vm);

    if(local == false){
        while(times--){
            _vm->updateVertex();
            for(auto &v:_vm->vert){
                Taubin(&v,lambda);
            }

            _vm->updateVertex();
            for(auto &v:_vm->vert){
                Taubin(&v,mu);
            }
        }
    }
    else{
        while(times--){
            _vm->updateVertex();
            for(auto &v:_vm->vert){
                if(v.IsS()){
                    continue;
                }
                Taubin(&v,lambda);
            }

            _vm->updateVertex();
            for(auto &v:_vm->vert){
                if(v.IsS()){
                    continue;
                }
                Taubin(&v,mu);
            }
        }
    }

}

void FairSurface::Taubin(vcgVertex *v,float scale)
{
    if (v->neighbors.empty()) {
        vcg::face::VFIterator<vcgFace>vfi(v);
        for (;!vfi.End();vfi++) {
            vcgFace *f = vfi.F();
            if (f->V(0)->id != v->id) {
                v->neighbors.insert(f->V(0)->id);
            }
            if (f->V(1)->id != v->id) {
                v->neighbors.insert(f->V(1)->id);
            }
            if (f->V(2)->id != v->id) {
                v->neighbors.insert(f->V(2)->id);
            }
        }
    }
    float W_ij = 1.0f / v->neighbors.size();
    for (auto s : v->neighbors) {
        v->P().X() += scale*W_ij*(_vm->vert[s].x - v->x);
        v->P().Y() += scale*W_ij*(_vm->vert[s].y - v->y);
        v->P().Z() += scale*W_ij*(_vm->vert[s].z - v->z);
    }
}
